package com.leal.myudf;

import java.math.BigInteger;
import java.util.Arrays;

/**
 * @Classname bigdata
 * @Description 写一个多线程案例
 * @Date 2024/8/27 16:11
 * @Created by leal
 */
public class MultiThreadPrint {

    public static final int NUMBER = 10000;
    public static final int THREAD_NUM = 5;

    // 写一个多线程案例和单线程比较的优势
    // 任务是打印1-1000，多线程启动10个线程分别打印1-100、100-200、200-300等，单线程打印1-1000
    public static void main(String[] args) throws InterruptedException {

        //singleThreadPrint();
        singleThreadPrintFactorials();
        multiThreadPrintFactorials();
    }

    private static void printNumbers(int start, int end) {
        for (int i = start; i <= end; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }

    private static void calculateAndPrintFactorials(int start, int end) {
        for (int i = start; i <= end; i++) {
            if (i % (THREAD_NUM * 100) == 0) {
                System.out.println(Thread.currentThread().getName() + "Factorial of " + i + ": " + factorialByBigInteger(i));
            }
        }
    }

    private static final BigInteger[] memo = new BigInteger[NUMBER + 1];

    static {
        Arrays.fill(memo, null);
        memo[0] = BigInteger.ONE;
        memo[1] = BigInteger.ONE;
    }

    private static BigInteger factorialByBigInteger(int n) {
        if (memo[n] != null) {
            return memo[n];
        }
        memo[n] = BigInteger.valueOf(n).multiply(factorialByBigInteger(n - 1));
        return memo[n];
    }

    private static long factorial(int n) {
        if (n <= 1) {
            return 1;
        }
        return n * factorial(n - 1);
    }

    private static void multiThreadPrintFactorials() throws InterruptedException {
        long startTime = System.currentTimeMillis();

        Thread[] threads = new Thread[THREAD_NUM];

        int counts = (int) (double) (NUMBER / THREAD_NUM);
        // 创建并启动线程
        for (int i = 0; i < THREAD_NUM; i++) {
            final int start = (i * counts) + 1;
            final int end = (i + 1) * counts;
            threads[i] = new Thread(() -> calculateAndPrintFactorials(start, end));
            threads[i].start();
        }

        for (Thread thread : threads) {
            thread.join();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("多线程执行耗时: " + (endTime - startTime) + " ms");
    }

    private static void singleThreadPrintFactorials() {
        long startTime = System.currentTimeMillis();

        for (int i = 1; i <= NUMBER; i++) {
            if (i % (THREAD_NUM * 100) == 0) {
                System.out.println(i + ": " + factorialByBigInteger(i));
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("单线程执行耗时: " + (endTime - startTime) + " ms");
    }

    private static void singleThreadPrint() {
        long startTime = System.currentTimeMillis();

        for (int i = 1; i <= 1000; i++) {
            System.out.println(i);
        }

        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;

        System.out.println("单线程执行耗时: " + duration + " ms");
    }

    private static void multiThreadPrint() throws InterruptedException {
        long startTime = System.currentTimeMillis();

        int numThreads = 10;
        Thread[] threads = new Thread[numThreads];

        // 创建并启动线程
        for (int i = 0; i < numThreads; i++) {
            final int start = (i * 100) + 1;
            final int end = (i + 1) * 100;
            threads[i] = new Thread(() -> printNumbers(start, end));
            threads[i].start();
        }

        // 等待所有线程结束
        for (Thread thread : threads) {
            thread.join();
        }

        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;

        System.out.println("多线程执行耗时: " + duration + " ms");
    }
}
